import {CommonClass} from "./CommonClass";
import {ConstVariable} from "../support/ConstVariable";

const defaultControlService = function () {
    let service = function () {
    };
    /**
     * 定义模块服务对象是否被控制器所托管, 此方法相对服务对象接口定义具备更高优先级
     * @param metaInfo 模块元数据
     * @param service 模块服务对象
     * @returns {boolean} 是否被拓宽
     */
    service.prototype.isUnderControl = function (metaInfo, service) {
        console.log("default control service");
        return false;
    };
    /**
     * 模块生命周期方法run执行前
     * @param interfaceName 接口名称
     * @param metaInfo 模块服务对象
     * @param service 模块服务对象
     */
    service.prototype.beforePresenterRun = function (interfaceName, metaInfo, service) {
        console.log("default control service");
    };
    /**
     * 模块生命周期方法run执行后
     * @param interfaceName 接口名称
     * @param metaInfo 模块服务对象
     * @param service 模块服务对象
     */
    service.prototype.afterPresenterRun = function (interfaceName, metaInfo, service) {
        console.log("default control service");
    };
    /**
     * 互动习题布局模块被设置之后
     * @param service 布局模块服务对象
     */
    service.prototype.afterSetLayoutService = function (service) {
        console.log("default control service");
    };
    /**
     * 定义控制器需要托管的模块服务类型, 以接口方法列表形式提供;
     * 当模块服务实现所有方法时, 该模块服务将被控制器所托管
     * @returns {Array} 控制器可管理模块服务接口对象
     * @example 返回对象定义 [{"name": "接口名称", "methods": [string array, 接口方法列表]}, {...}]
     */
    service.prototype.getInterfaceMethods = function () {
        console.log("default control service");
        return [];
    };

    return new service();
};


const CUSTOM_NAMESPACE = "__Custom";

class CommonController extends CommonClass {

    constructor(clazz = 'undefined', interfaceObj = undefined) {
        super(clazz, interfaceObj);
        this.metaInfo.type = ConstVariable.PresenterType.CONTROLLER;
        this._controlService = defaultControlService();
        //设置初始的Interface对象
        this._interface.processBeforeRun = this.processBeforeRun.bind(this);
        this._interface.processAfterRun = this.processAfterRun.bind(this);
        //控制服务列表
        this._serviceList = {};
        this._loadDeffers = {};
        this._layoutService = null;
        this._interceptPresenter = [];
        //是否只注入一次
        this._interceptOnce = true;
    }

    get InterceptOnce() {
        return this._interceptOnce;
    }

    set InterceptOnce(value) {
        if (typeof value === "boolean") {
            this._interceptOnce = value;
        }
    }

    get ControlService() {
        return this._controlService;
    }

    set ControlService(service) {
        //设置控制服务对象
        $.extend(this._controlService, service);
    }

    get __interface() {
        return this._interface;
    }

    get LayoutService() {
        return this._layoutService;
    }

    //对容器实现的接口方法,在每个模块被加载前会先运行该方法
    processBeforeRun(presenter = {getService: null, metaInfo: null}) {
        if (presenter.getService && presenter.metaInfo && typeof presenter.getService === "function") {
            const metaInfo = presenter.metaInfo, service = presenter.getService();
            if (service !== undefined && service['then']) {
                const identify = metaInfo.name + '@' + metaInfo._CLASS_ID_;
                if (this._loadDeffers[identify] === undefined) {
                    this._loadDeffers[identify] = $.Deferred();
                }
                service.then(()=> {
                    this._processService(metaInfo, presenter._service_);
                    if(this._loadDeffers[identify] && this._loadDeffers[identify].state() === "pending") {
                        this._loadDeffers[identify].resolve();
                    }
                });
            } else {
                this._processService(metaInfo, service);
            }

            //如果Presenter是功能组件
            if (metaInfo.type === ConstVariable.PresenterType.FUNCTIONAL) {
                const identify = metaInfo.name + '@' + metaInfo._CLASS_ID_, tKey = this.metaInfo.name + "-" + identify;
                presenter._handleOver_ = presenter._handleOver_ || {};
                presenter._handleOver_[tKey] = presenter._handleOver_[tKey] || $.Deferred();
            }
        }
    }

    processAfterRun(presenter = {getService: null, metaInfo: null, _handleOver_: null}) {
        if (presenter.getService && presenter.metaInfo && typeof presenter.getService === "function") {
            const metaInfo = presenter.metaInfo, classIdentify = metaInfo.name + '@' + metaInfo._CLASS_ID_;
            if (this._loadDeffers[classIdentify]) {
                this._loadDeffers[classIdentify]
                    .then(()=> {
                        this._processServiceAfter(metaInfo, classIdentify);
                        if(metaInfo.type === ConstVariable.PresenterType.FUNCTIONAL && presenter._handleOver_) {
                            presenter._handleOver_[this.metaInfo.name + "-" + classIdentify].resolve();
                        }
                    });
            } else {
                this._processServiceAfter(metaInfo, classIdentify);
                if (metaInfo.type === ConstVariable.PresenterType.FUNCTIONAL && presenter._handleOver_) {
                    presenter._handleOver_[this.metaInfo.name + "-" + classIdentify].resolve();
                }
            }
        }
    }

    _discoverInterface(identify, setting = {interface: "", methods: []}, metaInfo, service) {
        let isImplement = true;
        if (setting.methods.length === 0) {
            isImplement = false;
        } else {
            $.each(setting.methods, function (k, v) {
                if (service[v] === undefined) {
                    isImplement = false;
                    return false;
                }
            });
        }
        //如果接口有实现
        if (isImplement) {
            let exists = false;
            //检查是否已经添加过了
            $.each(this._serviceList[identify], function (k, v) {
                if (v.metaInfo.name === metaInfo.name && v.metaInfo._CLASS_ID_ === metaInfo._CLASS_ID_) {
                    exists = true;
                    return false;
                }
            });
            if (!exists) {
                this._serviceList[identify].push({metaInfo: metaInfo, service: service});
                this.ControlService.beforePresenterRun(setting.name, metaInfo, service);
            }
        }
    }

    _processService(metaInfo = {name: null, type: null}, service) {
        if (metaInfo.type === ConstVariable.PresenterType.LAYOUT && this._layoutService === null) {
            //如果是布局组件,做特殊处理; 为控制模块对象默认添加布局服务属性, 并执行afterSetLayoutService方法
            this._layoutService = service;
            this._controlService.afterSetLayoutService(service);
        }
        let interfaces = this._controlService.getInterfaceMethods();
        if (Array.isArray(interfaces) && interfaces.length > 0) {
            $.each(interfaces, (key, setting)=> {
                const identify = setting.name + '@' + metaInfo._CLASS_ID_;
                if (!this._serviceList[identify]) {
                    this._serviceList[identify] = [];
                }
                this._discoverInterface(identify, setting, metaInfo, service);
            });
        }
        //继续判断当前传入的Service对象是否服务控制对象自定义的控制条件
        if (this._controlService.isUnderControl(metaInfo, service)) {
            this._serviceList[CUSTOM_NAMESPACE] = this._serviceList["__Custom"] || [];
            let exists = false;
            $.each(this._serviceList[CUSTOM_NAMESPACE], (k, v)=> {
                if (v.metaInfo.name === metaInfo.name) {
                    exists = true;
                    return false;
                }
            });
            if (!exists) {
                this._serviceList[CUSTOM_NAMESPACE].push({metaInfo: metaInfo, service: service});
                //执行控制类方法
                this._controlService.beforePresenterRun(CUSTOM_NAMESPACE, metaInfo, service);
            }
        }
    }

    _processServiceAfter(metaInfo, identify) {
        if ($.inArray(identify, this._interceptPresenter) >= 0) {
            if (this.InterceptOnce) {
                return;
            }
        } else {
            this._interceptPresenter.push(identify);
        }

        const self = this;
        $.each(this._serviceList, (name, list)=> {
            const temp = name.split('@'), interfaceName = temp[0], classId = temp[1];
            $.each(list, (i, s)=> {
                if ((s.metaInfo.name + '@' + s.metaInfo._CLASS_ID_) === (metaInfo.name + '@' + metaInfo._CLASS_ID_)) {
                    self._controlService.afterPresenterRun(interfaceName, s.metaInfo, s.service);
                }
            });
        });
    }
}

export {CommonController};
